﻿using System;

class SelectBitsToExchange
{
    static void Main()
    {
        Console.WriteLine("A PROGRAM THAT EXCHANGES BITS {p,p+1,...,p+k-1} WITH BITS {q,q+1,...,q+k-1} OF A GIVEN 32-BIT UNSIGNED INTEGER.\r\n");
        Console.WriteLine("Enter an integer number:");

        //======================================================================================================
        string consoleInput = Console.ReadLine();
        uint number;
        //Number validation
        while (!UInt32.TryParse(consoleInput, out number))
        {
            Console.WriteLine("Invalid value. Enter another number:");
            consoleInput = Console.ReadLine();
        }

        int firstPosition; //Starting position of the first bit sequence
        int secondPosition; //Starting position of the second bit sequence
        int sequenceLength; //Length ot the bit sequence

        //p {0...30}, k {1...(32 - p)/2}, q {(p+k)...(32-k)} This is necessarry to prevent overlapping of the bits

        Console.WriteLine("\r\nEnter the start position \"p\" {0...30} for the first bit sequence:");
        Console.Write("p = ");
        consoleInput = Console.ReadLine();
        //Validation for the first start position "p"
        while ((!Int32.TryParse(consoleInput, out firstPosition)) || (firstPosition < 0) || (firstPosition > 30))
        {
            Console.WriteLine("Invalid value. Enter another number:");
            Console.Write("p = ");
            consoleInput = Console.ReadLine();
        }

        Console.WriteLine("\r\nEnter the length of the bit sequence \"k\" {1...(32 - p)/2}:"); //(32 - p)/2 is to prevent overriding of the bits
        Console.Write("k = ");
        consoleInput = Console.ReadLine();
        //Validation for the length of the bit sequence "k"
        while ((!Int32.TryParse(consoleInput, out sequenceLength)) || (sequenceLength > (32 - firstPosition)/2)
            || (sequenceLength < 1))
        {
            Console.WriteLine("Invalid value. Enter another number:");
            Console.Write("k = ");
            consoleInput = Console.ReadLine();
        }

        Console.WriteLine("\r\nEnter the start position \"q\" {(p+k)...(32-k)} for the second bit sequence");
        Console.Write("q = ");
        consoleInput = Console.ReadLine();
        //Validation for the second start position "q"
        while ((!Int32.TryParse(consoleInput, out secondPosition)) || (secondPosition < (firstPosition + sequenceLength))
            || (secondPosition > (32-sequenceLength)))
        {
            Console.WriteLine("Invalid value. Enter another number:");
            Console.Write("q = ");
            consoleInput = Console.ReadLine();
        }

        uint newNumber = number;
        long mask;
        uint numberAndMask; //Bitwise && expression 
        uint bitValueOne; // Value for bits {p, p+1,...p+k-1}
        uint bitValueTwo; // Value for bits {q, q+1,...q+k-1}
        int bitPositionOne; // Bit positions {p, p+1,...p+k-1}
        int bitPositionTwo; // Bit positions {q, q+1,...q+k-1}
        
        //This is the end of the validation part
        //=============================================================================================================

        for (bitPositionOne = firstPosition; bitPositionOne <= (firstPosition + sequenceLength-1); bitPositionOne++)
        {
            //Extracting the values of bits {p, p+1,...p+k-1}
            mask = Convert.ToUInt32(1U << bitPositionOne);
            numberAndMask = Convert.ToUInt32(newNumber & mask);
            bitValueOne = numberAndMask >> bitPositionOne;

            //Extracting the values of bits {q, q+1,...q+k-1}
            bitPositionTwo = secondPosition++;
            mask = Convert.ToUInt32(1U << bitPositionTwo);
            numberAndMask = Convert.ToUInt32(newNumber & mask);
            bitValueTwo = numberAndMask >> bitPositionTwo;

            //Setting the values of bits {p, p+1,...p+k-1} to the values of bits {q, q+1,...q+k-1}
            if (bitValueOne == 0)
            {
                //Seeting to 0
                mask = ~(1U << bitPositionTwo);
                newNumber = Convert.ToUInt32(newNumber & mask);
            }
            else
            {
                //Setting to 1
                mask = Convert.ToUInt32(1U << bitPositionTwo);
                newNumber = Convert.ToUInt32(newNumber | mask);
            }

            //Setting the values of bits {q, q+1,...q+k-1} to the values of bits {p, p+1,...p+k-1}
            if (bitValueTwo == 0)
            {
                mask = ~(1U << bitPositionOne);
                newNumber = Convert.ToUInt32(newNumber & mask);
            }
            else
            {
                mask = Convert.ToUInt32(1U << bitPositionOne);
                newNumber = Convert.ToUInt32(newNumber | mask);
            }
        }
        //Printing the result on the screen
        Console.WriteLine("\r\nThe result after the bits exchange is:\r\n");
        Console.Write("Old number: ");
        Console.Write(Convert.ToString(number).PadLeft(11));
        Console.Write("  ");
        Console.WriteLine(Convert.ToString(number, 2).PadLeft(32, '0'));
        Console.Write("New number: ");
        Console.Write(Convert.ToString(newNumber).PadLeft(11));
        Console.Write("  ");
        Console.WriteLine(Convert.ToString(newNumber, 2).PadLeft(32, '0'));
        Console.WriteLine();
    }
}